package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.model.CartInfo;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.product.model.SkuInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: atguigu
 * @create: 2023-09-13 10:51
 */
@Service
@SuppressWarnings("all")
public class CartInfoServiceImpl implements CartInfoService {


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    /**
     * 登录用户或者匿名用户-将商品加入到购物车
     *
     * @param isUser
     * @param userId
     * @param skuId
     * @param skuNum
     */
    @Override
    public void addToCart(boolean isUser, String userId, Long skuId, int skuNum) {
        //1.构建“用户”购物车hash结构key  user：用户ID：cart
        String cartKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        if (!isUser) {
            //临时用户
            redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
        }

        //2.创建Hash结构绑定操作对象（方便对hash进行操作）
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);


        //4.判断用户购物车中是否包含该商品 如果包含：数量进行累加(某件商品数量上限99) 不包含：新增购物车商品
        String hashKey = skuId.toString();
        Integer threshold = 99;
        if (hashOps.hasKey(hashKey)) {
            //4.1 说明该商品在购物车中已有，对数量进行累加 ，不能超过指定上限99
            CartInfo cartInfo = hashOps.get(hashKey);
            int totalCount = cartInfo.getSkuNum() + skuNum;
            cartInfo.setSkuNum(totalCount > threshold ? threshold : totalCount);
            hashOps.put(hashKey, cartInfo);
        } else {
            //3.判断购物车商品种类（不同SKU）总数大于50件
            Long count = hashOps.size();
            if (++count > 3) {
                throw new RuntimeException("商品种类数量超过上限！");
            }
            //4. 说明购物车没有该商品，构建购物车对象，存入Redis
            CartInfo cartInfo = new CartInfo();
            //4.1 远程调用商品服务获取商品基本信息
            cartInfo.setUserId(userId);
            cartInfo.setSkuNum(skuNum > threshold ? threshold : skuNum);
            cartInfo.setUpdateTime(new Date());
            cartInfo.setCreateTime(new Date());
            CompletableFuture<Void> skuInfoCompletableFuture = CompletableFuture.runAsync(() -> {
                SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
                cartInfo.setSkuId(skuId);
                cartInfo.setSkuName(skuInfo.getSkuName());
                cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());

            }, threadPoolExecutor);
            //4.2 远程调用商品服务获取商品实时价格
            CompletableFuture<Void> priceCompletableFuture = CompletableFuture.runAsync(() -> {
                BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
                cartInfo.setCartPrice(skuPrice);
                cartInfo.setSkuPrice(skuPrice);
            }, threadPoolExecutor);

            CompletableFuture.allOf(skuInfoCompletableFuture, priceCompletableFuture).join();

            //4.3 将购物车商品存入Redis
            hashOps.put(hashKey, cartInfo);
        }
    }


    /**
     * 查询指定“用户”购物车列表
     *
     * @param userId
     * @param userTempId
     * @return
     */
    //@Override
    //public List<CartInfo> getCartList(String userId, String userTempId) {
    //    //1.构建“用户”购物车Key
    //    String cartKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    //
    //    //2.创建绑定hash操作对象
    //    BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
    //
    //    //3.获取hash结构中value列表
    //    return hashOps.values();
    //}


    /**
     * 查询购物车列表，需要进行合并购物车
     *
     * @param userId     登录用户ID
     * @param userTempId 临时用户ID
     * @return
     */
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        //1.查询"临时用户未登录购物车”列表
        List<CartInfo> noLoginCartList = null;
        //1.1 如果临时用户ID有值，构建“未登录”购物车hash的Key
        if (StringUtils.isNotBlank(userTempId)) {
            String noLoginCartKey = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
            //1.2 创建未登录购物车绑定hash操作对象
            Boolean flag = redisTemplate.hasKey(noLoginCartKey);
            if (flag) {
                //1.3 查询“未登录”购物车列表
                BoundHashOperations<String, String, CartInfo> noLoginHashOps = redisTemplate.boundHashOps(noLoginCartKey);
                noLoginCartList = noLoginHashOps.values();
            }
        }
        //2.判断用户未登录-直接返回未登录购物车列表即可（记得排序）
        if (StringUtils.isBlank(userId) && !CollectionUtils.isEmpty(noLoginCartList)) {
            noLoginCartList = noLoginCartList.stream().sorted((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getCreateTime(), o1.getCreateTime(), Calendar.SECOND);
            }).collect(Collectors.toList());
            return noLoginCartList;
        }

        //3.代码到这里说明用户一定登录，且“未登录购物车集合”有数据-触发合并业务代码
        //3.0 构建已登录购物车Hash结构Key，以及对应绑定hash操作对象
        String loginCartKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        BoundHashOperations<String, String, CartInfo> loginhashOps = redisTemplate.boundHashOps(loginCartKey);
        //3.1 遍历未登录购物车列表
        if (!CollectionUtils.isEmpty(noLoginCartList)) {
            //3.2 判断已登录购物车Hash中是否包含未登录购物车商品
            Integer threshold = 99;
            for (CartInfo noLoginCartInfo : noLoginCartList) {
                String hashKey = noLoginCartInfo.getSkuId().toString();
                if (loginhashOps.hasKey(hashKey)) {
                    //3.2.1 如果包含：则对已登录购物车商品数量进行累加-不能超限
                    CartInfo cartInfo = loginhashOps.get(hashKey);
                    int totalCount = cartInfo.getSkuNum() + noLoginCartInfo.getSkuNum();
                    cartInfo.setSkuNum(totalCount > threshold ? threshold : totalCount);
                    loginhashOps.put(hashKey, cartInfo);
                } else {
                    //3.2.2 如果不包含：将未登录购物车商品商品变更用户ID后将购物车商品新增到已登录购物车
                    noLoginCartInfo.setUserId(userId);
                    loginhashOps.put(hashKey, noLoginCartInfo);
                }
            }
            //4.将"未登录购物车"删除
            String noLoginCartKey = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
            redisTemplate.delete(noLoginCartKey);
        }
        //5.再次查询已登录购物车列表（包含合并后的商品列表）
        List<CartInfo> loginCartList = loginhashOps.values();
        //6.按照商品加入购物车时间进行排序
        if (!CollectionUtils.isEmpty(loginCartList)) {
            loginCartList = loginCartList.stream().sorted((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getCreateTime(), o1.getCreateTime(), Calendar.SECOND);
            }).collect(Collectors.toList());
        }
        return loginCartList;
    }

    /**
     * 修改购物车商品选中状态
     *
     * @param userId
     * @param skuId
     * @param isChecked
     * @return
     */
    @Override
    public void checkCart(String userId, Long skuId, int isChecked) {
        BoundHashOperations<String, String, CartInfo> cartHashOps = getHashOps(userId);
        String hashkey = skuId.toString();
        if (cartHashOps.hasKey(hashkey)) {
            CartInfo cartInfo = cartHashOps.get(hashkey);
            cartInfo.setIsChecked(isChecked);
            cartHashOps.put(hashkey, cartInfo);
        }
    }

    /**
     * 根据传入“用户ID”返回hash操作对象
     *
     * @param userId
     * @return
     */
    private BoundHashOperations<String, String, CartInfo> getHashOps(String userId) {
        String cartKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        BoundHashOperations<String, String, CartInfo> cartHashOps = redisTemplate.boundHashOps(cartKey);
        return cartHashOps;
    }

    /**
     * 删除购物车商品
     *
     * @param request
     * @param skuId
     * @return
     */
    @Override
    public void deleteCart(String userId, Long skuId) {
        BoundHashOperations<String, String, CartInfo> cartHashOps = this.getHashOps(userId);
        cartHashOps.delete(skuId.toString());
    }

    /**
     * 查询用户购物车列表中选中商品列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        //1.根据用户ID返回操作购物车hash绑定对象
        BoundHashOperations<String, String, CartInfo> hashOps = this.getHashOps(userId.toString());

        //2.查询购物车列表
        List<CartInfo> cartInfoList = hashOps.values();

        //3.对购物车商品进行过滤找到选中购物车商品-isChecked=1商品
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList = cartInfoList.stream().filter(cartInfo -> {
                return (1 == cartInfo.getIsChecked());
            }).collect(Collectors.toList());
            return cartInfoList;
        }
        return cartInfoList;
    }

    @Override
    public void allCheckCart(String userId, Integer isChecked) {
        //1.构建用户购物车hash结构redisKey
        BoundHashOperations<String, String, CartInfo> hashOps = getHashOps(userId);
        //2.查询所有购物车商品列表
        List<CartInfo> cartInfoList = hashOps.values();

        //3.修改选中状态
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            for (CartInfo cartInfo : cartInfoList) {
                cartInfo.setIsChecked(isChecked);
                hashOps.put(cartInfo.getSkuId().toString(), cartInfo);
            }
        }
    }

    @Override
    public void clearCart(String userId) {
        //  获取购物车key
        String cartKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //  删除数据
        redisTemplate.delete(cartKey);
    }

}
